home *** CD-ROM | disk | FTP | other *** search
/ Nebula 1 / Nebula One.iso / Graphics / Viewers / aa_m68k_Intel_Only / ToyViewer1.2 / Source / ppmread.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-11-12  |  6.7 KB  |  324 lines

  1. #include  <stdio.h>
  2. #include  <stdlib.h>
  3. #include  <libc.h>
  4. #include  "ppm.h"
  5.  
  6. /* PPM Format
  7.     Px            : Header
  8.     Width Height
  9.     MAX            : pbm does not have this field
  10.     Bitmap        : in ASCII / Binary
  11. */
  12.  
  13. #define  PXOF        0xff
  14. #define  UnknownHD    0
  15. /* PX original Format
  16.     PX            : Header
  17.     Width Height Colors    : Colors := Number of colors in palette - 1
  18.     Palette        : Binary
  19.     Bitmap        : Binary
  20. */
  21.  
  22. static int ppmkind = 0, ppmmax = 0;
  23. static char ppmcomm[MAX_COMMENT];
  24.  
  25. static void ppm_skip(FILE *fp)
  26. {
  27.     int c;
  28.  
  29.     while ((c = getc(fp)) != EOF) {
  30.         if (c == '\n') {
  31.             c = getc(fp);
  32.             while (c == '#') {
  33.                 while ((c = getc(fp)) != '\n')
  34.                     if (c == EOF)
  35.                         return;
  36.                 c = getc(fp);
  37.             }
  38.         }
  39.         if (c > ' ') {
  40.             ungetc(c, fp);
  41.             return;
  42.         }
  43.     }
  44. }
  45.  
  46. static int ppm_head(FILE *fp)
  47. {
  48.     int c, i, kind = UnknownHD;
  49.  
  50.     if ((c = getc(fp)) != 'P')
  51.         return UnknownHD;
  52.     c = getc(fp);
  53.     if (c >= '0' && c <= '9')
  54.         kind = c - '0';
  55.     else if (c == 'X')
  56.         kind = PXOF;
  57.     ppmcomm[0] = 0;
  58.     while ((c = getc(fp)) <= ' ') ;
  59.     if (c == '#') {
  60.         for (i = 0; (c = getc(fp)) != '\n'; i++)
  61.             if (i < MAX_COMMENT-1) ppmcomm[i] = c;
  62.         ppmcomm[i] = 0;
  63.         ungetc('\n', fp);
  64.         ppm_skip(fp);
  65.     }else
  66.         ungetc(c, fp);
  67.     return kind;
  68. }
  69.  
  70. static int ppm_getint(FILE *fp)
  71. {
  72.     int c;
  73.     int v = 0;
  74.  
  75.     c = getc(fp);
  76.     while (c < '0' || c > '9') {
  77.         if (c == EOF) return -1;
  78.         c = getc(fp);
  79.     }
  80.     while (c >= '0' && c <= '9') {
  81.         v = (v * 10) + c - '0';
  82.         c = getc(fp);
  83.     }
  84.     if (c != EOF && c < ' ')
  85.         ungetc(c, fp);
  86.     return v;
  87. }
  88.  
  89.  
  90. commonInfo *loadPpmHeader(FILE *fp, int *errcode)
  91. {
  92.     int w, err;
  93.     commonInfo *cinf;
  94.  
  95.     *errcode = err = 0;
  96.     ppmkind = ppm_head(fp);
  97.     if (ppmkind == UnknownHD) {
  98.         *errcode = Err_FORMAT;
  99.         return NULL;
  100.     }
  101.     if ((w = ppm_getint(fp)) >= MAXWidth) {
  102.         *errcode = Err_IMPLEMENT;
  103.         return NULL;
  104.     }
  105.     if ((cinf = (commonInfo *)malloc(sizeof(commonInfo))) == NULL) {
  106.         *errcode = Err_MEMORY;
  107.         return NULL;
  108.     }
  109.     cinf->width = w;
  110.     cinf->alpha  = NO;
  111.     cinf->type = Type_ppm;
  112.     cinf->isplanar = YES;
  113.     cinf->palsteps = 0;
  114.     cinf->palette = NULL;
  115.     cinf->memo[0] = 0;
  116.     ppm_skip(fp);
  117.     cinf->height = ppm_getint(fp);
  118.     if (ppmkind == PBMa || ppmkind == PBMb) {
  119.         ppmmax = 2;
  120.         cinf->numcolors = 1;
  121.         (void)getc(fp);
  122.     }else {
  123.         ppm_skip(fp);
  124.         ppmmax = ppm_getint(fp) + 1;
  125.         (void)getc(fp);
  126.         if (ppmkind == PXOF) {
  127.             cinf->numcolors = 3;
  128.             cinf->xbytes = cinf->width;
  129.             cinf->bits = 8;
  130.             cinf->cspace = NX_RGBColorSpace;
  131.             return cinf;
  132.         }
  133.         cinf->numcolors = (ppmkind == PPMa || ppmkind == PPMb) ? 3 : 1;
  134.     }
  135.  
  136.     cinf->bits = (ppmmax > 16) ? 8
  137.             : ((ppmmax > 4) ? 4 : ((ppmmax > 2) ? 2 : 1));
  138.     cinf->xbytes = byte_length(cinf->bits, cinf->width);
  139.     cinf->cspace = (cinf->numcolors > 1) ? NX_RGBColorSpace
  140.             : ((ppmkind == PBMa || ppmkind == PBMb)
  141.                 ? NX_OneIsBlackColorSpace
  142.                 : NX_OneIsWhiteColorSpace);
  143.     return cinf;
  144. }
  145.  
  146.  
  147. static int isGrayPPM(unsigned char **planes, int length)
  148. {
  149.     int i;
  150.     unsigned char *rr, *gg, *bb;
  151.  
  152.     rr = planes[0];
  153.     gg = planes[1];
  154.     bb = planes[2];
  155.     for (i = 0; i < length; i++) {
  156.         if (rr[i] != gg[i] || gg[i] != bb[i]) return 0;
  157.     }
  158.     return 1;
  159. }
  160.  
  161. static int bitsOfPPM(unsigned char **planes, commonInfo *cinf)
  162. {
  163.     unsigned char *p, buf[256];
  164.     int i, pn, w, num;
  165.  
  166.     w = cinf->width * cinf->height;
  167.     for (i = 0; i < 256; i++) buf[i] = 0;
  168.     num = 0;
  169.     for (pn = 0; pn < cinf->numcolors; pn++) {
  170.         p = planes[pn];
  171.         for (i = 0; i < w; i++)
  172.             if (buf[p[i]] == 0) {
  173.                 buf[p[i]] = 1;
  174.                 if (++num > 16) return 8;
  175.             }
  176.     }
  177.     return optimalBits(buf, num);
  178. }
  179.  
  180. static int getPXOF(FILE *fp, commonInfo *cinf, unsigned char **planes)
  181. {
  182.     int    i, x, y;
  183.     unsigned char *p, *rr, *gg, *bb;
  184.  
  185.     cinf->palette = (paltype *)malloc(sizeof(paltype) * ppmmax);
  186.     if (cinf->palette == NULL)
  187.         return Err_MEMORY;
  188.     cinf->palsteps = ppmmax;
  189.     for (i = 0; i < ppmmax; i++) {
  190.         p = cinf->palette[i];
  191.         for (x = 0; x < 3; x++)
  192.             p[x] = getc(fp);
  193.     }
  194.     rr = planes[0];
  195.     gg = planes[1];
  196.     bb = planes[2];
  197.     for (y = 0; y < cinf->height; y++) {
  198.         for (x = 0; x < cinf->width; x++) {
  199.             p = cinf->palette[getc(fp)];
  200.             *rr++ = p[RED];
  201.             *gg++ = p[GREEN];
  202.             *bb++ = p[BLUE];
  203.         }
  204.     }
  205.     return 0;
  206. }
  207.  
  208. static int PPMplanes(FILE *fp,
  209.     commonInfo *cinf, int pn, unsigned char **planes)
  210. {
  211.     int    i, x, y;
  212.     unsigned char    work[3][MAXWidth];
  213.     int    width = cinf->width;
  214.  
  215.     for (y = 0; y < cinf->height; y++) {
  216.         if (feof(fp))
  217.             return Err_SHORT;
  218.         if (isPPMascii(ppmkind)) {
  219.             for (x = 0; x < width; x++)
  220.                 for (i = 0; i < pn; i++) {
  221.                 ppm_skip(stdin);
  222.                 work[i][x] = (ppm_getint(fp) << 8) / ppmmax;
  223.                 }
  224.         }else if (ppmkind == PBMb) {
  225.             int mask, cc;
  226.             for (x = 0; x < width; ) {
  227.                 cc = getc(fp);
  228.                 for (mask = 0x80; mask; mask >>= 1) {
  229.                     work[0][x] = (cc & mask) ? 0xff : 0;
  230.                     if (++x >= width) break;
  231.                 }
  232.             }
  233.         }else {
  234.             for (x = 0; x < width; x++) {
  235.                 for (i = 0; i < pn; i++)
  236.                 work[i][x] = (getc(fp) << 8) / ppmmax;
  237.             }
  238.         }
  239.         for (i = 0; i < pn; i++) {
  240.             unsigned char *pp = planes[i] + y * cinf->xbytes;
  241.             packImage(pp, work[i], width, cinf->bits);
  242.         }
  243.     }
  244.     return 0;
  245. }
  246.  
  247. int ppmGetImage(FILE *fp,
  248.     commonInfo *cinf, unsigned char **planes, const char *fkind)
  249. {
  250.     int    i, y, pn, bits, err;
  251.     int    width, xbyte;
  252.     const char *kp;
  253.  
  254.     width = cinf->width;
  255.     pn = cinf->numcolors;
  256.     err = allocImage(planes, width, cinf->height, cinf->bits, (pn == 1));
  257.     if (err) return err;
  258.     if (ppmkind == PXOF)
  259.         err = getPXOF(fp, cinf, planes);
  260.     else
  261.         err = PPMplanes(fp, cinf, pn, planes);
  262.     if (err) return err;
  263.  
  264.     /* Is the image Gray ? */
  265.     if (pn == 3 && isGrayPPM(planes, cinf->xbytes * cinf->height)) {
  266.         size_t newsize = planes[1] - planes[0];
  267.         planes[0] = (unsigned char *)realloc(planes[0], newsize);
  268.         planes[1] = planes[2] = NULL;
  269.         pn = cinf->numcolors = 1;
  270.         cinf->cspace = NX_OneIsWhiteColorSpace;
  271.     }
  272.     /* How many bits are needed ? */
  273.     if (cinf->bits == 8 && (bits = bitsOfPPM(planes, cinf)) < 8) {
  274.         unsigned char *src, *dst, *newmap[3];
  275.         err = allocImage(newmap, width, cinf->height, bits, (pn == 1));
  276.         if (err) return 0; /* Error */
  277.         xbyte = byte_length(bits, width);
  278.         for (i = 0; i < pn; i++) {
  279.             src = planes[i];
  280.             dst = newmap[i];
  281.             for (y = 0; y < cinf->height; y++) {
  282.                 packImage(dst, src, width, bits);
  283.                 src += width;
  284.                 dst += xbyte;
  285.             }
  286.         }
  287.         free((void *)planes[0]);
  288.         for (i = 0; i < 3; i++)
  289.             planes[i] = newmap[i];
  290.         cinf->xbytes = xbyte;
  291.         cinf->bits = bits;
  292.     }
  293.  
  294.     sprintf(cinf->memo, "%d x %d  ", cinf->width, cinf->height);
  295.     kp = fkind ? fkind
  296.         : ((ppmkind == PXOF) ? "PXOF" : PPMname(ppmkind));
  297.     strcat(cinf->memo, kp);
  298.     if ((bits = cinf->bits) == 1)
  299.         strcat(cinf->memo, " 1bit");
  300.     else {
  301.         i = strlen(cinf->memo);
  302.         sprintf(cinf->memo + i, " %dbits%s", bits,
  303.                 (planes[1] ? "" : ", gray"));
  304.     }
  305.     if (ppmcomm[0]) {
  306.         strcat(cinf->memo, " : ");
  307.         i = strlen(cinf->memo);
  308.         strncat(cinf->memo, ppmcomm, MAX_COMMENT - i - 2);
  309.     }
  310.  
  311.     return 0;
  312. }
  313.  
  314. #ifdef _TEST
  315. main()
  316. {
  317.     printf("kind=P%d\n", ppm_head(stdin));
  318.     while (!feof(stdin)) {
  319.         ppm_skip(stdin);
  320.         printf("%d\n", ppm_getint(stdin));
  321.     }
  322. }
  323. #endif
  324.